#include <rsa.h>
#include <QString>
#include <QByteArray>
#include <openssl/evp.h>
#include <stdio.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <QDebug>

#define RSA_PRIKEY_PSW "123"

static const char rnd_seed[] = "www.kylinos.cn";

#define PRIVATE_KEY_FILE "/tmp/avit.data.tmp1"
#define PUBLIC_KEY_FILE  "/tmp/avit.data.tmp2"

int rsa::generate_key_files(const char *pub_keyfile, const char *pri_keyfile,
                       const unsigned char *passwd, int passwd_len)
{
    RSA *rsa = RSA_new();
    BIGNUM *bne = BN_new();
    BN_set_word(bne, RSA_F4);
    RAND_seed(rnd_seed, sizeof(rnd_seed));

    int ret = RSA_generate_key_ex(rsa, 2048 , bne, NULL);
    if(ret != 1)
    {
        qDebug()<<("RSA_generate_key error!\n");
        return -1;
    }

    // 生成公钥文件
    BIO *bp = BIO_new(BIO_s_file());
    if(NULL == bp)
    {
        qDebug()<<"generate_key bio file new error!\n";
        RSA_free(rsa);
        return -1;
    }

    if(BIO_write_filename(bp, (void *)pub_keyfile) <= 0)
    {
        qDebug()<<"BIO_write_filename error!\n";
        RSA_free(rsa);
        return -1;
    }

    if(PEM_write_bio_RSAPublicKey(bp, rsa) != 1)  //将公钥写入公钥文件中
    {
        qDebug()<<"PEM_write_bio_RSAPublicKey error!\n";
        RSA_free(rsa);
        return -1;
    }

    // 公钥文件生成成功，释放资源
//    qDebug()<<("Create public key ok!\n");
    BIO_free_all(bp);


    // 生成私钥文件
    bp = BIO_new_file(pri_keyfile, "w+");
    if(NULL == bp)
    {
        printf("generate_key bio file new error2!\n");
        return -1;
    }

    if(PEM_write_bio_RSAPrivateKey(bp, rsa,EVP_des_ede3_ofb(), (unsigned char *)passwd, passwd_len, NULL, NULL) != 1)
    {
        printf("PEM_write_bio_RSAPublicKey error!\n");
        return -1;
    }

    // 释放资源
//    qDebug()<<("Create private key ok!\n");
    BIO_free_all(bp);

    return 0;
}

// 打开公钥文件，返回EVP_PKEY结构的指针
EVP_PKEY* rsa::open_public_key(const char *keyfile)
{
    EVP_PKEY* key = NULL;
    RSA *rsa = NULL;

    OpenSSL_add_all_algorithms();
    BIO *bp = BIO_new(BIO_s_file());;
    BIO_read_filename(bp, keyfile);
    if(NULL == bp)
    {
        printf("open_public_key bio file new error!\n");
        return NULL;
    }

    rsa = PEM_read_bio_RSAPublicKey(bp, NULL, NULL, NULL);
    if(rsa == NULL)
    {
        printf("open_public_key failed to PEM_read_bio_RSAPublicKey!\n");
        BIO_free(bp);
        RSA_free(rsa);

        return NULL;
    }

//    qDebug()<<("open_public_key success to PEM_read_bio_RSAPublicKey!\n");
    key = EVP_PKEY_new();
    if(NULL == key)
    {
        printf("open_public_key EVP_PKEY_new failed\n");
        RSA_free(rsa);

        return NULL;
    }

    EVP_PKEY_assign_RSA(key, rsa);
    return key;
}

// 打开私钥文件，返回EVP_PKEY结构的指针
EVP_PKEY* rsa::open_private_key(const char *keyfile, const unsigned char *passwd)
{
    EVP_PKEY* key = NULL;
    RSA *rsa = RSA_new();
    OpenSSL_add_all_algorithms();
    BIO *bp = NULL;
    bp = BIO_new_file(keyfile, "rb");
    if(NULL == bp)
    {
        printf("open_private_key bio file new error!\n");

        return NULL;
    }

    rsa = PEM_read_bio_RSAPrivateKey(bp, &rsa, NULL, (void *)passwd);
    if(rsa == NULL)
    {
        printf("open_private_key failed to PEM_read_bio_RSAPrivateKey!\n");
        BIO_free(bp);
        RSA_free(rsa);

        return NULL;
    }

//    qDebug()<<("open_private_key success to PEM_read_bio_RSAPrivateKey!\n");
    key = EVP_PKEY_new();
    if(NULL == key)
    {
        printf("open_private_key EVP_PKEY_new failed\n");
        RSA_free(rsa);

        return NULL;
    }

    EVP_PKEY_assign_RSA(key, rsa);
    return key;
}

int rsa::rsa_key_encrypt(EVP_PKEY *key, const unsigned char * orig_data, size_t orig_data_len,
                    unsigned char * enc_data, size_t &enc_data_len)  //enc_data是已加密的数据
{
    EVP_PKEY_CTX *ctx = NULL;
    OpenSSL_add_all_ciphers();

    ctx = EVP_PKEY_CTX_new(key, NULL);
    if(NULL == ctx)
    {
        printf("ras_pubkey_encryptfailed to open ctx.\n");
        EVP_PKEY_free(key);
        return -1;
    }

    if(EVP_PKEY_encrypt_init(ctx) <= 0)
    {
        printf("ras_pubkey_encryptfailed to EVP_PKEY_encrypt_init.\n");
        EVP_PKEY_free(key);
        return -1;
    }

    EVP_PKEY_encrypt(ctx, NULL, &enc_data_len, orig_data, orig_data_len);

    enc_data = (unsigned char*)calloc(1,enc_data_len);

    int ret = EVP_PKEY_encrypt(ctx, enc_data, &enc_data_len, orig_data, orig_data_len);

    if(ret <= 0)
    {
        qDebug()<<("ras_pubkey_encryptfailed to EVP_PKEY_encrypt.\n");
        EVP_PKEY_CTX_free(ctx);
        EVP_PKEY_free(key);

        return -1;
    }
    EVP_PKEY_CTX_free(ctx);
    EVP_PKEY_free(key);

    return 0;
}


int rsa::rsa_key_decrypt(EVP_PKEY *key, const unsigned char *enc_data, size_t enc_data_len,
                    unsigned char *dec_data, size_t &dec_data_len)
{
    EVP_PKEY_CTX *ctx = NULL;
    OpenSSL_add_all_ciphers();

    ctx = EVP_PKEY_CTX_new(key, NULL);
    if(NULL == ctx)
    {
        printf("ras_prikey_decryptfailed to open ctx.\n");
        EVP_PKEY_free(key);
        return -1;
    }

    if(EVP_PKEY_decrypt_init(ctx) <= 0)
    {
        printf("ras_prikey_decryptfailed to EVP_PKEY_decrypt_init.\n");
        EVP_PKEY_free(key);
        return -1;
    }

    EVP_PKEY_decrypt(ctx,NULL, &dec_data_len, enc_data, enc_data_len);

    dec_data = (unsigned char*)calloc(1,dec_data_len);

    int ret=EVP_PKEY_decrypt(ctx, dec_data, &dec_data_len, enc_data, enc_data_len);

    if(ret<= 0)
    {
        qDebug()<<("ras_prikey_decryptfailed to EVP_PKEY_decrypt.\n");
        EVP_PKEY_CTX_free(ctx);
        EVP_PKEY_free(key);

        return -1;
    }

    EVP_PKEY_CTX_free(ctx);
    EVP_PKEY_free(key);
    return 0;
}

bool rsa::encrypt(const QByteArray origin_data, QByteArray &enc_data, size_t &enc_data_len)
{
    QByteArray date = origin_data.toHex();  //将一个个字符转成10进制数字对应的16进制数字，字节长度是原来的两倍
    enc_data_len=512;
    generate_key_files(PUBLIC_KEY_FILE, PRIVATE_KEY_FILE, (const unsigned char *)RSA_PRIKEY_PSW, strlen(RSA_PRIKEY_PSW));
    EVP_PKEY *pub_key = open_public_key(PUBLIC_KEY_FILE);
    rsa_key_encrypt(pub_key, (const unsigned char*)date.data(), date.size(), (unsigned char*)enc_data.data(), enc_data_len);
    return 0;
}

bool rsa::decrypt(const QByteArray enc_data, size_t enc_data_len, QByteArray &dec_data, size_t &dec_data_len)
{
    QByteArray tmp;
    dec_data_len=512;
    EVP_PKEY *pri_key = open_private_key(PRIVATE_KEY_FILE, (const unsigned char *)RSA_PRIKEY_PSW);
    rsa_key_decrypt(pri_key, (const unsigned char*)enc_data.data(), enc_data_len,(unsigned char*)tmp.data(), dec_data_len);
    QByteArray tmp2 = tmp.data();
    tmp2.resize(dec_data_len);
    dec_data = QByteArray::fromHex(tmp2);
    tmp.clear();
    tmp.squeeze();
    tmp2.clear();
    tmp2.squeeze();
    return 0;
}
